App.require(["htmlTool"], function (htmlTool) {
    var app = App.getCurrent();

    app.defineComponent("str-data-table", {
        render: function (next) {
            this.computedData();
            this.data.dataList = [];
            this.fetch("./index.html", function (text) {
                this.data.html = text;
                next(this.renderHTML(text));
            })
        },
        getDomObj: function () {
            this.attachDom("table", "table")
                .attachEvent("table", "togglechange", this.toggleChangeHandler, false)
                .attachEvent("table", "iconclick", this.iconClickHandler, false)
                .attachEvent("table", "btnclick", this.btnClickHandler, false);
        },
        toggleChangeHandler: function (ev) {
            var component = ev.detail.component, ppNode = component.nodes[0].parentNode.parentNode.parentNode;
            if (ppNode.tagName.toUpperCase() === "THEAD") {
                this.selectAll(component.checked);
            }
            else if (ppNode.tagName.toUpperCase() === "TBODY") {
                this.selectAside();
            }
            var data = this.getBodySelectData();
            this.dispatchCustomEvent("tablechange", {
                component: this,
                data: data,
                event: ev
            })
        },
        getBodySelectData: function () {
            var components = this.getComponentsByTagName("str-toggle").filter(function (item) {
                return item.dataset.action == "checked";
            });
            var tBodyComponents = components.slice(1), result = [];

            for (var i = 0; i < tBodyComponents.length; i++) {
                if (tBodyComponents[i].checked) result.push(this.data.dataList[i]);
            }
            return result;
        },
        selectAside: function () {
            if (!this.property.checkable) return;
            var components = this.getComponentsByTagName("str-toggle").filter(function (item) {
                return item.dataset.action == "checked";
            });
            var tBodyComponents = components.slice(1);
            var isSelectAll = true, hasSelected = false;
            for (var i = 0; i < tBodyComponents.length; i++) {
                var com = tBodyComponents[i], isCheck = com.checked;
                isSelectAll = isSelectAll && isCheck
                hasSelected = hasSelected || isCheck
                this.data.dataList[i].checked = isCheck;
            }
            if (isSelectAll) {
                components[0].indeterminate = false;
                components[0].checked = true;
            }
            else if (hasSelected) components[0].indeterminate = true;
            else {
                components[0].indeterminate = false;
                components[0].checked = false;
            }
        },
        selectAll: function (isCheck) {
            var components = this.getComponentsByTagName("str-toggle").filter(function (item) {
                return item.dataset.action == "checked";
            })
            isCheck = !!isCheck;
            components[0].indeterminate = false;
            components[0].checked = isCheck;
            for (var i = 1; i < components.length; i++) {
                components[i].checked = isCheck;
                this.data.dataList[i - 1].checked = isCheck;
            }
        },
        iconClickHandler: function (ev) {
            var component = ev.detail.component;
            var td = component.nodes[0].parentNode, that = this;
            switch (component.icon) {
                case "circle-edit-outline":
                    var oldValue = td.firstChild.nodeValue;
                    var input = document.createElement("input");
                    input.type = "text";
                    input.value = oldValue;
                    td.removeChild(td.firstChild);
                    this.insertAdjacentHTML(td, '<str-text label="' + "修改" + '" value="' + oldValue + '" size="small" hiddenbottom></str-text>', "afterbegin", function () {
                        var textDom = that.getComponentByDom(td, "str-text");
                        if (textDom) {
                            textDom.focus();
                            textDom.select();
                        }
                        component.icon = "content-save-outline";
                    });
                    break;
                case "content-save-outline":
                    var textDom = this.getComponentByDom(td, "str-text");
                    var value = textDom ? textDom.value : "";
                    var obj = this.getComputedUpdateData(td.parentNode, td, value);
                    var event = this.getCanCancelEvent();
                    this.dispatchCustomEvent("tablecontentchange", {
                        component: this,
                        data: obj,
                        event: event,
                        target: component
                    });
                    if (!event.isCancel) {
                        component.icon = "circle-edit-outline";
                        this.updateByEditCellData(obj.index, obj.tIndex, obj.key, value);
                    }
                    break;
                case "arrow-down-drop-circle-outline":
                    var row = td.parentNode;
                    var data = this.getDataByRow(row).data;
                    var event = this.getCanTransDataEvent();
                    this.dispatchCustomEvent("tableexpanddata", {
                        data: data,
                        event: event
                    });
                    var transdata = event.getData();
                    if (transdata) component.icon = "arrow-up-drop-circle-outline";
                    if (typeof transdata === "function") {
                        transdata(function (data) {
                            that.expandDataByRow(row, data);
                        })
                    }
                    else if (typeof transdata === "string") {
                        that.expandDataByRow(row, transdata);
                    }
                    break;
                case "arrow-up-drop-circle-outline":
                    this.removeNextRow(td.parentNode);
                    component.icon = "arrow-down-drop-circle-outline";
                    break;
                case "arrow-down":
                    var name = this.getOptionName(td);
                    var event = this.getCanTransDataEvent();
                    this.dispatchCustomEvent("tablesort", {
                        key: name,
                        event: event
                    });
                    var transdata = event.getData();
                    if (transdata && typeof transdata === "function") {
                        var dataList = this.data.dataList.sort(transdata);
                        this.initData(dataList);
                    }
                    break;
            }
        },
        getOptionName: function (td) {
            var row = td.parentNode, tds = row.children, index = 0;
            for (var i = 0; i < tds.length; i++) {
                if (tds[i] == td) {
                    index = i;
                    break;
                }
            }
            if (this.property.checkable) index--;
            return this.data.options[index].data;
        },
        removeNextRow: function (row) {
            var tbody = this.domList.table.tBodies[0], index = 0;
            var rows = tbody.rows;
            for (var i = 0; i < rows.length; i++) {
                if (rows[i] === row) {
                    index = i;
                    break;
                }
            }
            tbody.deleteRow(index + 1);
        },
        expandDataByRow: function (row, str) {
            var len = row.children.length, tbody = this.domList.table.tBodies[0], index = 0;
            var rows = tbody.rows;
            for (var i = 0; i < rows.length; i++) {
                if (rows[i] === row) {
                    index = i;
                    break;
                }
            }
            var insertRow = tbody.insertRow(index + 1);
            insertRow.dataset.type = "expand";
            var cell = insertRow.insertCell();
            cell.colSpan = len;
            this.innerHTML(cell, str);
            
        },
        updateByEditCellData: function (index, tIndex, key, value) {
            var data = this.data.dataList[index], row = this.domList.table.tBodies[0].rows[index], td = row.children[tIndex];
            var dom = this.getComponentByDom(td, "str-text");
            this.removeComponent(dom);
            this.insertAdjacentHTML(td, value, "afterbegin", function () {
                data[key] = value;
            });
        },
        getDataByRow: function (row) {
            var tbody = this.domList.table.tBodies[0];
            var rows = tbody.rows, index = 0;
            var dataRows = [];
            for (var i = 0; i < rows.length; i++) {
                if (!rows[i].dataset.type) dataRows.push(rows[i]);
            }
            for (var i = 0; i < dataRows.length; i++) {
                if (dataRows[i] == row) {
                    index = i;
                    break;
                }
            }
            return {
                data: this.data.dataList[index],
                index: index
            }
        },
        getComputedUpdateData: function (row, td, value) {
            var obj = this.getDataByRow(row);
            var changeData = JSON.parse(JSON.stringify(obj.data)), index = obj.index;
            var tds = row.children, tIndex = 0;
            for (var i = 0; i < tds.length; i++) {
                if (tds[i] == td) {
                    tIndex = i;
                    break;
                }
            }
            var dataKey = this.data.options[this.property.checkable ? tIndex - 1: tIndex].data;
            changeData[dataKey] = value;
            return {
                index: index,
                tIndex: tIndex,
                value: value,
                key: dataKey,
                data: changeData
            }
        },
        getComponentByDom: function (dom, name) {
            var components = this.getComponentsByTagName(name);
            for (var i = 0; i < components.length; i++) {
                if (dom.contains(components[i].nodes[0])) return components[i];
            }
            return null;
        },
        btnClickHandler: function (ev) {
            var component = ev.detail.component;
            var tr = Component.getNodeName(component.nodes[0], "TR");
            if (tr) {
                var data = this.getDataByRow(tr);
                this.dispatchCustomEvent("tablebtnclick", {
                    event: ev,
                    data: data.data, 
                    action: component.dataset.action
                })
            }
        },
        init: function () {
            this.selectAside();
        },
        initData: function (list) {
            this.data.dataList = list;
            var table = this.domList.table;
            var tbody = table.tBodies[0]; 
            var rows = tbody.rows, components = this.components;
            for (var i = components.length - 1; i >= 0; i--) {
                if (tbody.contains(components[i].nodes[0])) {
                    this.removeComponent(components[i]);
                }
            }

            for (var i = rows.length - 1; i >= 0; i--) {
                tbody.deleteRow(i);
            }


            if (list.length > 0) {
                for (var i = 0; i < list.length; i++) {
                    var row = tbody.insertRow(), data = list[i];
                    if (this.property.checkable) {
                        var cell = row.insertCell();
                        this.innerHTML(cell, "<str-toggle data-action='checked'" + (data.checked ? "checked" : "") + "></str-toggle>");
                    }
                    if (this.property.hasindex) {
                        var cell = row.insertCell();
                        cell.classList.add("cell-center");
                        this.innerHTML(cell, i + 1);
                    }
                    for (var j = 0; j < this.data.options.length; j++) {
                        var cell = row.insertCell(), item = this.data.options[j], html = ""; 
                        if (item.data) {
                            if (item.filter) {
                                var filter = this._getFilter(item.filter);
                                if (filter) html = filter.func.call(filter.target, data[item.data]);
                                else html = data[item.data]
                            }
                            else html = data[item.data];
                        }
                        else html = item.content;
                        if (item.editable) html += '<str-icon class="ripple" icon="circle-edit-outline" width="16" height="16"></str-icon>';
                        if (item.expandable) html += '<str-icon data-expandable="' + item.expandable  + '" class="ripple" icon="arrow-down-drop-circle-outline" width="16" height="16"></str-icon>';
                        this.innerHTML(cell, html);
                    }
                }
            }
            else {
                var row = tbody.insertRow(), cell = row.insertCell();
                cell.colSpan = this.data.colLength;
                cell.align = "center";
                cell.classList.add("tr-no-data");
                cell.appendChild(document.createTextNode("暂无数据"));
            }

            this.selectAside();
        },
        computedSlot: function (html) {
            var pattern = /<str-data-table[^>]*?>([\s\S]*?)<\/str-data-table>/g;
            var matches = pattern.exec(html);
            if (matches) return matches[1];
            return "";
        },
        computedData: function () {
            var property = this.property;
            this.data.options = htmlTool.getOptions(this.slot);
            property.class = property.class || "";
            property.border = typeof property.border === "undefined" ? "1" : property.border; 
            property.checkable = typeof property.checkable !== "undefined" ? "checkable" : "";
            property.hasindex = typeof property.hasindex !== "undefined";
            property.caption = property.caption || "";
            property.key = property.key || "id";
            this.data.colLength = this.data.options.length + (property.checkable ? 1 : 0)  + (property.hasindex ? 1 : 0);
            this.data.propertystr = this.createPropertyStr();
        },
        addCheckBox: function () {
            var table = this.domList.table, tHead = table.tHead, tbody = table.tBodies[0];
            var trows = tHead.rows[0], tbrows = tbody.rows;
            
            var feeback = function () {
                if (--len == 1) that.selectAside();
            }
            var brows = [];
            for (var i = 0; i < tbrows.length; i++) {
                if (tbrows[i].dataset.type !== "expand") brows.push(tbrows[i]);
            }
            var len = brows.length + 1, that = this;
            var cell = trows.insertCell(0);
            this.innerHTML(cell, '<str-toggle data-action="checked"></str-toggle>', feeback);

            for (var i = 0; i < brows.length; i++) {
                var cell = brows[i].insertCell(0);
                this.innerHTML(cell, '<str-toggle data-action="checked" ' + (this.data.dataList[i].checked ? "checked" : "") + '></str-toggle>', feeback)
            }
            var expandDom = this.domList.table.querySelectorAll('[data-type="expand"]');
            for (var i = 0; i < expandDom.length; i++) {
                expandDom[i].children[0].colSpan += 1;
            }
        },
        removeCheckBox: function () {
            var checkComponents = this.getComponentsByTagName("str-toggle").filter(function (item) {
                return item.dataset.action == "checked";
            });
            for (var i = checkComponents.length - 1; i >= 0; i--) {
                var com = checkComponents[i];
                var td = com.nodes[0].parentNode;
                this.removeComponent(com);
                td.remove();
            }
            var expandDom = this.domList.table.querySelectorAll('[data-type="expand"]');
            for (var i = 0; i < expandDom.length; i++) {
                expandDom[i].children[0].colSpan -= 1;
            }
        },
        get checkable() {
            return this.property.checkable;
        },
        set checkable(value) {
            value = value ? "checkable" : "";
            if (this.property.checkable === value) return;
            this.property.checkable = value;
            if (value) this.addCheckBox();
            else this.removeCheckBox();
        },
        get caption() {
            return this.property.caption;
        },
        set caption(value) {
            if (this.property.caption == value) return;
            var oldCpation = this.property.caption;
            if (oldCpation) {
                if (value) this.domList.table.caption.textContent = value;
                else this.domList.table.deleteCaption();
            }
            else {
                var caption = this.domList.table.createCaption();
                caption.textContent = value;
            }
            this.property.caption = value;
        },
        get key() {
            return this.property.key;
        },
        set key(id) {
            if (this.property.key === id) return;
            this.property.key = id;
        },
        get className() {
            return this.property.class;
        },
        set className(value) {
            if (this.property.class === value) return;
            this.domList.table.className = value;
            this.property.class = value;
        },
        filter: {
            computedIndexName: function (str) {
                if (str) return str;
                return "序号";
            }
        }
    })
})